<?php
/**
 * @version 	$Id: fSession.class.php 74 2010-03-17 06:48:21Z mylifeisskidrow@gmail.com $
 * @author 		$Author: mylifeisskidrow $
 * @copyright 	Copyright (c) 2010 Luu Trong Hieu. All right reserved.
 * @license 	GNU/GPL see license.php
 */

defined('IN_FLYWHEEL') or die('Restricted Access!');

/**
 * Session
 * 
 * @package 	system
 * @subpackage 	session
 *
 */

class fSession {
	const STATE_ACTIVE = 1,
		STATE_EXPIRED = 2,
		STATE_DESTROYED = 3,
		STATE_ERROR = 4;
		
	protected $store = null;
	/**
	 * Configs
	 *
	 * @var array
	 */		
	protected $_configs = array();
	/**
	 * Expire
	 * Maximum age of unused session
	 *
	 * @var int	 
	 */	
	protected $_expire = 900;
	
	/**
	 * internal state
	 *	 
	 * @var	string $_state one of 'active'|'expired'|'destroyed|'error'	 
	 */
	protected $_state = self::STATE_ACTIVE;
	
	/**
	 * Time start
	 *
	 * @var int
	 */
	protected $_startTime;
	
	/**
	 * Last Time
	 *
	 * @var int
	 */
	protected $_lastTime;
	
	/**
	 * Current Time
	 *
	 * @var int
	 */
	protected $_currentTime;
	
	public function __construct($configs = array()) {
		//Need to destroy any existing sessions started with session.auto_start
		if (session_id()) {
			session_unset();
			session_destroy();
		}
		$this->_getConfig($configs);
		$this->_start();
		$flashSessions = $this->getSessionData('flash/new');
		if (is_array($flashSessions) && sizeof($flashSessions) > 0) {
			$this->set('flash/old', array_keys($flashSessions));
		}
		
		if (!$this->has('start', 'timer')) {			
			$time = time();
			$this->set('start', $time, 'timer');
			$this->set('last', $time, 'timer');
			$this->set('current', $time, 'timer');
			$this->_startTime = $this->_lastTime = $this->_currentTime = $time;
		}
		else {
			$this->_startTime = $this->get('start', 'timer');
			$this->_lastTime = $this->get('last', 'timer');
			$this->_currentTime = $this->get('current', 'timer');
		}
		
	}
	
	public function getState() {
		return $this->_state;
	}
	
	public function getExpire() {
		return $this->_expire;
	}
	
	/**
	 * Get Token
	 *
	 * @param boolean $reset. default = false
	 * @return string
	 */
	public function getToken($reset = false) {
		$token = $this->get('token');
		if ($token === null || $reset) {
			$token = $this->createToken();
			$this->set('token', $token);	
		}
		
		return $token;
	}
	
	/**
	 * Start Session
	 *
	 * @return boolean
	 */
	private function _start() {
		session_cache_limiter('none');
		session_start(true);

		// Send modified header for IE 6.0 Security Policy
		header('P3P: CP="NOI ADM DEV PSAi COM NAV OUR OTRo STP IND DEM"');

		return true;		
	}
	
/**
	 * Set data into the session store
	 *
	 * @access public
	 * @param  string $name  		Name of a variable
	 * @param  mixed  $value 		Value of a variable
	 * @param  string 	$namespace 	Namespace to use, default to 'default'
	 * @return boolean
	 */
	public function set($name, $value, $namespace = 'default') {
		$namespace = '__'.$namespace; //add prefix to namespace to avoid collisions

		if (null === $value) {
			unset($_SESSION[$namespace][$name]);
		} else {
			$_SESSION[$namespace][$name] = $value;
		}
		
		return true;
	}
	
	/**
	 * Get
	 * 	get session value
	 *
	 * @param string $name
	 * @param string $namspace
	 * @return mixed
	 */
	public function get($name, $namespace = 'default') {
		$namespace = '__'.$namespace;
		return $_SESSION[$namespace][$name];		 
	}
	
	/**
	 * Has
	 * 	check exist session value
	 *
	 * @param string $name
	 * @param string $namespace
	 * @return boolean
	 */
	public function has($name, $namespace = 'default') {
		$namespace = '__'.$namespace;
		return isset($_SESSION[$namespace][$name]);		
	}
	
	/**
	 * Sets a flash variable that will be passed to the very next action.
	 *
	 * @param  string $name     The name of the flash variable
	 * @param  string $value    The value of the flash variable
	 */
	public function setFlash($name, $value) {
		$this->set($name, $value, 'flash/new');
		$this->remove($name, 'flash/old');		
	}
	
	/**
	 * Gets a flash variable.
	 *
	 * @param  string $name     The name of the flash variable
	 * @return mixed The value of the flash variable
	 */
	public function getFlash($name) {
		return $this->get($name, 'flash/new');
	}
	
	/**
	 * Remove
	 *
	 * @param string $name
	 * @param string $namespace
	 * @return void
	 */
	public function remove($name, $namespace = 'default') {
		unset($_SESSION['__'.$namespace][$name]);
	}
	
	/**
	 * Get Session Data
	 *
	 * @param string $namespace
	 * @return array
	 */
	public function getSessionData($namespace = null) {
		if ($namespace === null) return $_SESSION;
		$namespace = '__'.$namespace;
		return $_SESSION[$namespace];		
	}
	
	/**
	 * Get Config
	 *
	 * @param array $configs
	 */
	private function _getConfig($configs) {		
		if (isset($configs['name'])) {
			session_name(md5($configs['name']));
		}
		
		if (isset($configs['filetime'])) {
			$this->_expire = fFilter::clean($configs['filetime'], fFilter::TYPE_INT)*60;			
		}
		ini_set('session.gc_maxlifetime', $this->_expire);
	}
	
	/**
	 * Validate
	 * 
	 * @return boolean $result true on success
	 *
	 */
	public function validate() {
		if ($this->_expire > 0) {
			$currentTime = (int) $this->get('timer.now');
			$lifeTime = ((int) $this->get('timer.last')) + $this->_expire;

			if ($lifeTime < $currentTime) {
				$this->_state = self::STATE_EXPIRED;
				return false;								
			}
		}
	}
	
	/**
	* Create a token-string
	*
	* @access protected
	* @param int $length lenght of string
	* @return string $id generated token
	*/
	public function createToken($length = 32)
	{
		$chars	=	'!@#$%^&*()0123456789abcdef';
		$max			=	strlen( $chars ) - 1;
		$token			=	'';
		$name 			=  session_name();
		for( $i = 0; $i < $length; ++$i ) {
			$token .=	$chars[ (rand( 0, $max )) ];
		}

		return md5($token.$name.php_uname());
	}
	
	/**
	 * Create Session Id
	 *
	 * @return md5 string
	 */
	private function _createSessionId() {
		$id = 0;
		while (strlen($id) < 32)  {
			$id .= mt_rand(0, mt_getrandmax());
		}

		$id	= md5( uniqid($id, true));
		return $id;		
	}	
	
	public function close() {
		$flashOld = $this->get('flash/old');
		for ($i = 0, $size = sizeof($flashOld); $i < $size; ++$i) {
			$this->remove($flashOld[$i]);			
		}
		session_write_close();
	}
	
	public function __destruct() {
		$this->close();
	}
}